package com.yupi.apiback.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yupi.apiback.common.ErrorCode;
import com.yupi.apiback.exception.BusinessException;
import com.yupi.apiback.mapper.InterfaceInfoMapper;
import com.yupi.apiback.model.dto.interfaceInfo.InterfaceAddRequest;
import com.yupi.apiback.model.dto.interfaceInfo.InterfaceInvokingRequest;
import com.yupi.apiback.model.dto.interfaceInfo.InterfacePageRequest;
import com.yupi.apiback.model.dto.interfaceInfo.InterfaceUpdateRequest;
import com.yupi.apiback.model.entity.InterfaceInfo;
import com.yupi.apiback.model.entity.SuperModel;
import com.yupi.apiback.model.entity.User;
import com.yupi.apiback.model.enums.interfaceInfo.InterfaceInfoStatusEnum;
import com.yupi.apiback.model.enums.interfaceInfo.MethodTypeEnum;
import com.yupi.apiback.model.enums.user.UserRoleEnum;
import com.yupi.apiback.service.InterfaceInfoService;
import com.yupi.apiback.service.UserService;
import com.yupi.apiinvoksdk.model.dto.InvokingParams;
import com.yupi.apiinvoksdk.utils.ApiClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author yanghaifeng
 * @description 针对表【interface_info(接口信息)】的数据库操作Service实现
 * @createDate 2024-01-18 15:49:55
 */
@Service
public class InterfaceInfoServiceImpl extends ServiceImpl<InterfaceInfoMapper, InterfaceInfo>
        implements InterfaceInfoService {

    @Autowired
    private UserService userService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean add(InterfaceAddRequest dto) {
        // 公共校验
        this.addAndEditCommonCheck(dto, null);
        InterfaceInfo interfaceInfo = BeanUtil.toBean(dto, InterfaceInfo.class);
        return this.save(interfaceInfo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean remove(Long id) {
        // 请参校验
        this.getInterfaceInfo(id);
        // 删除接口
        return this.removeById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long edit(InterfaceUpdateRequest dto) {
        Long id = dto.getId();
        if (ObjectUtil.isNull(id) || id < 1) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 公共校验
        this.addAndEditCommonCheck(dto, id);
        // 数据入库
        InterfaceInfo interfaceInfo = BeanUtil.toBean(dto, InterfaceInfo.class);
        this.updateById(interfaceInfo);
        return id;
    }

    @Override
    public InterfaceInfo queryDetails(Long id) {
        return this.getInterfaceInfo(id);
    }

    @Override
    public Page<InterfaceInfo> page(InterfacePageRequest condition, Page<InterfaceInfo> page, HttpServletRequest request) {
        String methodType = condition.getMethodType();
        String status = condition.getStatus();

        // 请参校验
        // 枚举是否匹配校验
        if (StrUtil.isNotBlank(methodType)) {
            MethodTypeEnum.getKeyEnum(methodType);
        }
        if (StrUtil.isNotBlank(status)) {
            InterfaceInfoStatusEnum.getKeyEnum(status);
        }

        // 分页
        // 获取当前登录用户，检查其角色是否为管理员，不是管理员只能查看已上线的接口
        User loginUser = userService.getLoginUser(request);
        String userRole = loginUser.getUserRole();
        Page<InterfaceInfo> result = new Page<>();
        if (UserRoleEnum.ADMIN.getKey().equals(userRole)) {
            result = baseMapper.adminPage(condition, page);
        } else {
            result = baseMapper.userPage(condition, page);
        }
        return result;
    }

    @Override
    public Boolean removeList(List<Long> ids) {
        if (ObjectUtil.isEmpty(ids)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        return this.removeBatchByIds(ids);
    }

    @Override
    public Boolean online(Long id) {
        // 获取接口信息
        InterfaceInfo interfaceInfo = this.getInterfaceInfo(id);
        // 接口是否是为上线
        String status = interfaceInfo.getStatus();
        if (InterfaceInfoStatusEnum.OPEN.getKey().equals(status)) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "接口已上线");
        }
        if (InterfaceInfoStatusEnum.CLOSE.getKey().equals(status)) {
            // 上线接口
            interfaceInfo.setStatus(InterfaceInfoStatusEnum.OPEN.getKey());
            this.updateById(interfaceInfo);
        }
        return true;
    }

    @Override
    public Boolean offline(Long id) {
        // 获取接口信息
        InterfaceInfo interfaceInfo = this.getInterfaceInfo(id);
        // 接口是否是为上线
        String status = interfaceInfo.getStatus();
        if (InterfaceInfoStatusEnum.CLOSE.getKey().equals(status)) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "接口已下线");
        }
        if (InterfaceInfoStatusEnum.OPEN.getKey().equals(status)) {
            // 上线接口
            interfaceInfo.setStatus(InterfaceInfoStatusEnum.CLOSE.getKey());
            this.updateById(interfaceInfo);
        }
        return true;
    }

    @Override
    public Object invoking(InterfaceInvokingRequest dto, HttpServletRequest request) {
        // 获取当前登录用户
        User loginUser = userService.getLoginUser(request);

        // 检查接口是否可以调用
        Long id = dto.getId();
        String userRequestParams = dto.getRequestParams();
        InterfaceInfo interfaceInfo = this.getInterfaceInfo(id);
        // 校验发起接口调用所需要的数据是否存在，如：url、请求参数（如果数据库请求参数存在，而用户提交的请求参数不存在则报错）
        String url = interfaceInfo.getUrl();
        if (StrUtil.isBlank(url)) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "接口无请求地址");
        }
        String requestParams = interfaceInfo.getRequestParams();
        if (StrUtil.isNotBlank(requestParams)) {
            if (StrUtil.isNotBlank(userRequestParams)) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "该接口需要请求参数");
            }
        }

        // 使用SDK发起接口调用
        InvokingParams params = new InvokingParams();
        params.setUrl(url);
        Map<String, String> map = new HashMap<>();
        map.put("userName", "mini");
        String jsonStr = JSONUtil.toJsonStr(map);
        params.setBody(jsonStr);
        ApiClient apiClient = new ApiClient(loginUser.getAccessKey(), loginUser.getSecretKey());
        return apiClient.interfaceInvoking(params);
    }

    /**
     * 获取接口信息
     *
     * @param id 接口Id
     * @return 接口信息
     */
    private InterfaceInfo getInterfaceInfo(Long id) {
        // id not null && !< 1
        if (ObjectUtil.isNull(id) || id < 1) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 校验接口是否存在
        InterfaceInfo interfaceInfo = this.getById(id);
        if (ObjectUtil.isNull(interfaceInfo)) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "接口不存在");
        }
        return interfaceInfo;
    }


    /**
     * 新增和修改公共校验
     *
     * @param dto 接口信息
     * @param id  接口Id
     */
    private void addAndEditCommonCheck(InterfaceAddRequest dto, Long id) {
        String name = dto.getName();
        String url = dto.getUrl();
        String methodType = dto.getMethodType();
        String status = dto.getStatus();
        if (StrUtil.hasBlank(name, url, methodType, status)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 枚举是否匹配校验
        MethodTypeEnum.getKeyEnum(methodType);
        InterfaceInfoStatusEnum.getKeyEnum(String.valueOf(status));
        // 封装查询条件
        LambdaQueryWrapper<InterfaceInfo> queryWrapper = Wrappers.lambdaQuery(InterfaceInfo.class);
        queryWrapper.eq(InterfaceInfo::getUrl, url);
        // 根据Id判断是新增还是修改
        if (ObjectUtil.isNotNull(id)) {
            // 接口是否存在
            InterfaceInfo interfaceInfo = this.getById(id);
            if (ObjectUtil.isNull(interfaceInfo)) {
                throw new BusinessException(ErrorCode.OPERATION_ERROR, "接口不存在");
            }
            // url不能重复,需要排出自己
            queryWrapper.ne(SuperModel::getId, id);
        }
        // url不能重复，未删除的情况下
        long count = this.count(queryWrapper);
        if (count != 0) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "接口Url不能重复");
        }
    }
}




